<?php

declare(ENCODING = 'UTF-8');

/*                                                                        *
 * This script is part of the TYPO3 project - inspiring people to share!  *
 *                                                                        *
 * TYPO3 is free software; you can redistribute it and/or modify it under *
 * the terms of the GNU General Public License version 2 as published by  *
 * the Free Software Foundation.                                          *
 *                                                                        *
 * This script is distributed in the hope that it will be useful, but     *
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN-    *	
 * TABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General      *
 * Public License for more details.                                       *
 *                                                                        */	

/**
 * @package auxo
 * @subpackage Logging
 * @version $Id$
 */

/**	
 * The Logger
 *	
 * @package auxo
 * @subpackage Logging
 * @version $Id$	
 * @copyright Copyright belongs to the respective authors
 * @author AHN
 * @license http://opensource.org/licenses/gpl-license.php GNU Public License, version 2
 */
class  tx_auxo_Logger  {
	
	/*
	 * Nothing to log at all
	 */
	const	NONE	= 0;

	/*
	 * Information level
	 */
	const	INFO	= 1;
	
	/*
	 * level for warning messages
	 */
	const	WARNING	= 2;
	
	/*
	 * level for error messages
	 */
	const	ERROR	= 4;
	
	/*
	 * level for fatal messages
	 */
	const	FATAL	= 8;
	
	/*
	 * level for debug messages
	 */
	const	DEBUG	= 16;

	/*
	 * level for trace messages
	 */
	const	TRACE	= 32;

	/*
	 * Combined all log levels
	 */
	const	ALL		= 255;
	
	/**
	 * A appender registery 
	 *
	 * @var tx_auxo_LogAppenderInterface
	 */
	private $appenders = array();
	
	/**
	 * Defines a log level
	 *
	 * @var int
	 */
	private $level = 0;
	
	/**
	 * Creates a new Logger and passes an appender optionally. It also is possible
	 * to inject a appender via method {@link setAppender}.
	 *
	 * @param t_auxo_LogAppenderInterface $appender
	 */
	public function __construct(t_auxo_LogAppenderInterface $appender=NULL) {
		if ($appender) {
			$this->setAppender($appender);
		}
	}
	
	/**
	 * Injects a appender to this logger 
	 * 
	 * You might inject more than one appender to a logger in order 
	 * to output your log entries to multiple channels simutanously.
	 *
	 * @param tx_auxo_LogAppenderInterface $appender
	 */
	public function setAppender(tx_auxo_LogAppenderInterface $appender) {
		$this->appenders[spl_object_hash($appender)] = $appender;
	}
	
	/**
	 * Sets a log level
	 * 
	 * Please notice, log levels might be combined using PHP's bitwise OR 
	 * operator.
	 * <code>
	 * 	 ...->setLevel(tx_auxo_Logger::INFO | tx_auxo_Logger::WARNING);
	 * </code>
	 * This activates logging of information and warning messages.
	 * 
	 * @param int $level log level
	 */
	public function setLevel($level) {
		$this->level = $level;
	}
	
	/**
	 * Logs a debug message
	 *
	 * @param string $string
	 * @return boolean $logged returns true if this message was logged
	 */
	public function debug($string) {
		return $this->log(self::DEBUG, $string);		
	}

	/**
	 * Logs a trace message
	 *
	 * @param string $string
	 * @return boolean $logged returns true if this message was logged
	 */
	public function trace($string) {
		return $this->log(self::TRACE, $string);
	}

	/**
	 * Logs a information message
	 *
	 * @param string $string
	 * @return boolean $logged returns true if this message was logged
	 */
	public function info($string) {
		return $this->log(self::INFO, $string);
	}


	/**
	 * Logs a warning message
	 *
	 * @param string $string
	 * @return boolean $logged returns true if this message was logged
	 */
	public function warning($string) {
		return $this->log(self::WARNING, $string);		
	}
	
	/**
	 * Logs a error message
	 *
	 * @param string $string
	 * @return boolean $logged returns true if this message was logged
	 */
	public function error($string) {
		return $this->log(self::ERROR, $string);
	}

	/**
	 * Logs a fatal message
	 *
	 * @param string $string
	 * @return boolean $logged returns true if this message was logged
	 */
	public function fatal($string) {
		return $this->log(self::FATAL, $string);
	}
	
	/**
	 * Closes this logger and all registered appenders
	 *
	 * @return void
	 */
	public function close() {
		foreach ($this->appenders as $appender) {
			$appender->close();
		}
	}
	
	/**
	 * Returns true if a certain log level has been activated
	 *
	 * @param int $level
	 * @return boolean $activated true if $level has been enabled
	 */
	public function isEnabled($level) {
		return ($level & $this->level);
	}
	
	/**
	 * Logs $data with all registered appender if $level 
	 *
	 * @param int $level log level
	 * @param mixed $data data to log
	 * @return boolean $added true if data have been appended
	 */
	protected function log($level, $data) {	
		if (! $this->isEnabled($level)) {
			return false;
		}
		
		if( ! is_string($data)) {
			ob_start();
			var_dump($data);
			$string = ob_get_contents();
			ob_end_clean();
		}
		else {
			$string = $data;
		}
		
		$event = $this->setSourceCodeDetails(new tx_auxo_LogEvent($level, $string));
		
		foreach ($this->appenders as $appender) {
			$appender->append($event);		
		}
		
		return true;
	}
	
	/**
	 * Determines file, line, class, method of a log call and fills a log event
	 * with this information
	 *
	 * @param tx_auxo_LogEvent $event incoming event
	 * @return tx_auxo_LogEvent $event event with source code details
	 */
	protected function setSourceCodeDetails(tx_auxo_LogEvent $event) {
		$backtrace = debug_backtrace();
		if (isset($backtrace[2])) {
			$trace = $backtrace[2];
			$event->setSourceCodeDetails($trace['file'], $trace['line'], $trace['class'] . $trace['type'] . $trace['function']);
		}
		return $event;
	}
}